package com.vinoxm.rss.redis;

import com.alibaba.fastjson.JSON;
import com.vinoxm.rss.model.RssSubscribe;
import com.vinoxm.rss.model.RssTracker;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class RedisClient {

    private static long expire = 60 * 20;

    protected static void setExpire(Long expire) {
        RedisClient.expire = expire;
    }

    private static RedisTemplate<String, Object> baseRedisTemplate;

    protected static void setBaseRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        if (RedisClient.baseRedisTemplate == null) RedisClient.baseRedisTemplate = redisTemplate;
    }

    private static RedisTemplate<String, RssTracker> trackerRedisTemplate;

    protected static void setTrackerRedisTemplate(RedisTemplate<String, RssTracker> redisTemplate) {
        if (RedisClient.trackerRedisTemplate == null) RedisClient.trackerRedisTemplate = redisTemplate;
    }

    /**
     * RSS_UPDATING
     */
    private final static String RSS_UPDATING = "rss-updating";

    public static boolean isRssUpdating() {
        return Boolean.TRUE.equals(baseRedisTemplate.hasKey(RSS_UPDATING));
    }

    public static void setRssUpdating(boolean flag) {
        if (flag) {
            baseRedisTemplate.opsForValue().set(RSS_UPDATING, 1, expire, TimeUnit.SECONDS);
        } else {
            baseRedisTemplate.delete(RSS_UPDATING);
        }
    }

    /**
     * RSS_SEASON_HASH
     */
    private final static String RSS_SEASON_HASH = "rss-season-hash";

    public static void flushRssSubsBySeason(List<RssSubscribe> rssArray, String season) {
        Map<String, Object> map = new HashMap<>();
        map.put(season, JSON.toJSONString(rssArray));
        baseRedisTemplate.opsForHash().putAll(RSS_SEASON_HASH, map);
        baseRedisTemplate.expire(RSS_SEASON_HASH, expire, TimeUnit.SECONDS);
    }

    public static void removeRssSubsBySeason(String season) {
        baseRedisTemplate.opsForHash().delete(RSS_SEASON_HASH, season);
    }

    public static void removeRssSubsBySeason(List<String> season) {
        baseRedisTemplate.opsForHash().delete(RSS_SEASON_HASH, season.toArray());
    }

    public static Boolean hasRssSubsSeason(String season) {
        return baseRedisTemplate.opsForHash().hasKey(RSS_SEASON_HASH, season);
    }

    public static List<RssSubscribe> getRssSubsBySeason(String season) {
        Object json = baseRedisTemplate.opsForHash().get(RSS_SEASON_HASH, season);
        return json == null ? null : JSON.parseArray(json.toString(), RssSubscribe.class);
    }

    /**
     * RSS_SEASON_OPTIONS
     */
    private final static String RSS_SEASON_OPTIONS = "rss-season-options";

    public static void setSeasonOptions(List<String> seasonOps) {
        baseRedisTemplate.opsForSet().add(RSS_SEASON_OPTIONS, seasonOps.toArray());
    }

    public static boolean hasSeasonOptions() {
        return Boolean.TRUE.equals(baseRedisTemplate.hasKey(RSS_SEASON_OPTIONS));
    }

    public static Set<Object> getSeasonOptions() {
        return baseRedisTemplate.opsForSet().members(RSS_SEASON_OPTIONS);
    }

    public static Boolean isSeasonOptionsMember(String season) {
        return baseRedisTemplate.opsForSet().isMember(RSS_SEASON_OPTIONS, season);
    }

    /**
     * RSS_TRACKER_LIST
     */
    private final static String RSS_TRACKER_LIST = "rss-tracker-list";

    public static List<RssTracker> setTrackerList(List<RssTracker> list) {
        trackerRedisTemplate.delete(RSS_TRACKER_LIST);
        trackerRedisTemplate.opsForList().rightPushAll(RSS_TRACKER_LIST, list);
        return list;
    }

    public static List<RssTracker> getTrackerList() {
        return Boolean.TRUE.equals(trackerRedisTemplate.hasKey(RSS_TRACKER_LIST)) ? trackerRedisTemplate.opsForList().range(RSS_TRACKER_LIST, 0, -1) : null;
    }

    /**
     * RSS_REGEX_SORTED_SET
     */
    private final static String RSS_REGEX_SORTED_SET = "rss-regex-sorted-set";
    private final static long incrStep = 10000000000L;

    public static void addRssRegex(String regex) {
        long timestamp = System.currentTimeMillis() / 1000;
        if (Boolean.FALSE.equals(baseRedisTemplate.boundZSetOps(RSS_REGEX_SORTED_SET).addIfAbsent(regex, incrStep + timestamp))) {
            baseRedisTemplate.boundZSetOps(RSS_REGEX_SORTED_SET).incrementScore(regex, incrStep);
        }
    }

    public static Set<?> getRssRegex(int range) {
        return baseRedisTemplate.boundZSetOps(RSS_REGEX_SORTED_SET).reverseRange(0, range - 1);
    }
}
